package cn.csc.framework.pay.core.client.impl.jh;

import cn.csc.framework.pay.core.client.PayCommonResult;
import cn.csc.framework.pay.core.client.dto.*;
import cn.csc.framework.pay.core.enums.PayNotifyRefundStatusEnum;
import cn.csc.framework.pay.core.enums.channel.PayChannelEnum;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import static cn.csc.framework.common.util.json.JsonUtils.toJsonString;
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
import static cn.hutool.core.date.DatePattern.PURE_DATETIME_FORMATTER;

@Slf4j
public class JHLitePayClient extends AbstractJHClient {

    public JHLitePayClient(BigInteger channelId, JHPayClientConfig config) {
        super(channelId, PayChannelEnum.JH_WX.getCode(), config, new JHPayCodeMapping());
    }

    @Override
    protected PayCommonResult<?> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Throwable {
        return null;
    }

    @Override
    protected PayOrderUnifiedRespDTO doUnifiedBeanOrder(PayOrderUnifiedReqDTO reqDTO) {
        try {
            Map<String, String> map = jHPayService.pay(
                    reqDTO.getMerchantOrderId(),
                    formatAmount(reqDTO.getAmount()),
                    "",
                    "",
                    reqDTO.getUserIp(),
                    "",
                    reqDTO.getSubject(),
                    "",
                    reqDTO.getChannelExtras().get("tradeType"),
                    reqDTO.getChannelExtras().get("wxAppId"),
                    reqDTO.getChannelExtras().get("openId")
                     );
            log.info("[JHLitePayClient][doUnifiedBeanOrder]map:{}",map);

            // 支付成功
            if("000000".equals(map.get("ERRCODE").toString())){
                return  PayOrderUnifiedRespDTO.successOf(map.get("nonceStr").toString(),"",
                        "",reqDTO.getMerchantOrderId(),reqDTO.getMerchantOrderId(),
                        map, null);
            }
            //支付失败
            log.info("[JHLitePayClient][doUnifiedBeanOrder]{}",map);
            return PayOrderUnifiedRespDTO.closedOf(map.get("ERRCODE").toString(),map.get("ERRMSG").toString(),
                    reqDTO.getMerchantOrderId(), map);
        } catch (Exception e) {
            log.error("[[doUnifiedOrder][request({})调用建行支付异常]", toJsonString(reqDTO), e);
            throw new RuntimeException(e.getMessage(),e);
        }
    }

    /**
     * 从支付宝通知返回参数中解析 PayOrderNotifyRespDTO, 通知具体参数参考
     * //https://opendocs.alipay.com/open/203/105286
     *
     * @param data 通知结果
     * @return 解析结果 PayOrderNotifyRespDTO
     * @throws Exception 解析失败，抛出异常
     */
    @Override
    public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception {
        Map<String, String> params = data.getParams();
        Map<String, String> bodyObj = HttpUtil.decodeParamMap(data.getBody(), StandardCharsets.UTF_8);

        return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("cusorderid"))
                .channelOrderNo(bodyObj.get("trxid"))
                .tradeStatus("trxstatus").successTime(parseMuchTime(params.get("paytime")))
                .build();
    }

    @Override
    public PayRefundNotifyRespDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
        Map<String, String> params = strToMap(notifyData.getBody());
        PayRefundNotifyRespDTO notifyDTO = PayRefundNotifyRespDTO.builder().channelOrderNo(params.get("trade_no"))
                .tradeNo(params.get("out_trade_no"))
                .reqNo(params.get("out_biz_no"))
                .status(PayNotifyRefundStatusEnum.SUCCESS)
                .refundSuccessTime(LocalDateTimeUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))
                .rawData(notifyData.getBody())
                .build();
        return notifyDTO;
    }

    @Override
    public boolean isRefundNotify(PayNotifyDataDTO notifyData) {
        if (notifyData.getParams().containsKey("refund_fee")) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean verifyNotifyData(PayNotifyDataDTO notifyData) {
        boolean verifyResult = false;
        try {
//            TreeMap<String, String> map = new TreeMap<>();
//            map.putAll(notifyData.getParams());
//            verifyResult = SybUtil.validSign(map, config.getPrivateKeyContent(), config.getSignType());
        } catch (Exception e) {
            log.error("[TLPayClient verifyNotifyData][(notify param is :{}) 验证失败]", toJsonString(notifyData.getParams()), e);
        }
        return verifyResult;
    }



    /**
     * 支付宝统一回调参数  str 转 map
     *
     * @param s 支付宝支付通知回调参数
     * @return map 支付宝集合
     */
    public static Map<String, String> strToMap(String s) {
        // TODO @zxy：这个可以使用 hutool 的 HttpUtil decodeParams 方法么？
        Map<String, String> stringStringMap = new HashMap<>();
        // 调整时间格式
        String s3 = s.replaceAll("%3A", ":");
        // 获取 map
        String s4 = s3.replace("+", " ");
        String[] split = s4.split("&");
        for (String s1 : split) {
            String[] split1 = s1.split("=");
            stringStringMap.put(split1[0], split1[1]);
        }
        return stringStringMap;
    }

    @Override
    public Object parseNotify(PayNotifyReqDTO rawNotify) {
        log.info("[JHLitePayClient][parseNotify]{},{}",rawNotify.getBody(),rawNotify.getBody());
        // 1. 校验回调数据
        String body = rawNotify.getBody();
        Map<String, String> params = rawNotify.getParams();
        Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);

        // 2.1 退款的情况
        if (bodyObj.containsKey("refundfee")) {
           //暂无退款
        }
        // 2.2 支付的情况
        // 解码参数
        return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("ORDERID"))
                .channelOrderNo("jh_wx")
                .tradeStatus(params.get("SUCCESS")).successTime(LocalDateTime.now())//parseMuchTime(params.get("ACCDATE"))
                .build();

    }

    protected LocalDateTime parseMuchTime(String str) {
        LocalDateTime t1 = LocalDateTimeUtil.parse(str, PURE_DATETIME_FORMATTER);
        String t2 = LocalDateTimeUtil.format(t1, NORM_DATETIME_FORMATTER);
        return LocalDateTimeUtil.parse(t2, NORM_DATETIME_FORMATTER);
    }


}
